package com.autonavi.yunda.yunji.service;

import com.autonavi.yunda.yunji.common.exception.AmapException;
import com.autonavi.yunda.yunji.common.exception.AmapExceptionCode;
import com.autonavi.yunda.yunji.common.exception.AmapPreconditions;
import com.autonavi.yunda.yunji.common.utils.JsonUtils;
import com.autonavi.yunda.yunji.common.utils.http.HttpClient;
import com.autonavi.yunda.yunji.common.utils.http.vo.HttpResponse;
import com.autonavi.yunda.yunji.core.config.ApplicationEnvConfig;
import com.autonavi.yunda.yunji.core.enums.BpmsCallBackType;
import com.autonavi.yunda.yunji.core.model.constants.PartUnitConstants;
import com.autonavi.yunda.yunji.core.model.dto.PartUnitDTO;
import com.autonavi.yunda.yunji.core.service.PartUnitService;
import com.autonavi.yunda.yunji.service.model.BpmsTaskVO;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import okhttp3.FormBody;
import okhttp3.Request;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class BPMSFlowService {

    private static final HttpClient httpClient = new HttpClient();

    @Value("${yunji.bpms.service.host}")
    private String bpmsService;
    @Value("${yunji.bpms.apiTestFlow.processCode}")
    private String processCode;
    @Value("${yunji.bpms.apiTestFlow.authKey}")
    private String authKey;
    @Resource
    private ApplicationEnvConfig applicationEnvConfig;
    @Resource
    private PartUnitService partUnitService;

    /**
     * 发起接口测试审批流程
     */
    public String startTestBPMSFlow(Long interfaceId,
                                    String commitUserId,
                                    List<String> approvalUserIds,
                                    String testComment) {
        PartUnitDTO partUnitDTO = partUnitService.findByIdOrThrow(interfaceId);
        AmapPreconditions.checkArgumentForUser(CollectionUtils.isNotEmpty(approvalUserIds), "审批人不能为空");
        String falconId = partUnitDTO.getFalconId();
        AmapPreconditions.checkArgumentForUser(StringUtils.isNotBlank(falconId), "接口还未填写falconId");
        Map<String, Object> initDataMap
                = Map.of(
                "callBackType", BpmsCallBackType.UPDATE_PART_UNIT_TEST_STATUS.name(),
                "approvalUserIds", JsonUtils.toString(approvalUserIds),
                "interfaceId", interfaceId.toString(),
                "interfaceName", partUnitDTO.getTitle(),
                "falconId", falconId,
                "falconUrl", PartUnitConstants.SOURCE_PREFIX + falconId,
                "testComment", testComment == null ? "" : testComment,
                "env", applicationEnvConfig.getEnv().getCode()
        );
        return startBPMSFlow(commitUserId, applicationEnvConfig.getEnv().getDesc() + ":API测试审批", authKey, processCode, initDataMap);
    }

    private String startBPMSFlow(String commitUserId,
                                 String title,
                                 String authKey,
                                 String processCode,
                                 Map<String, Object> initDataMap) {
        String serviceURL = this.bpmsService + "/openapi/processInstanceService/startProcessInstance.json";
        Request.Builder builder = new Request.Builder();
        builder.url(serviceURL);
        FormBody formBody = new FormBody.Builder()
                .add("authKey", authKey)
                .add("processCode", processCode)
                .add("title", title)
                .add("orginatorId", commitUserId)
                .add("initData", JsonUtils.toString(initDataMap))
                .build();
        builder.post(formBody);
        Map<String, Object> contentMap = doExecute(builder, serviceURL);
        return (String) contentMap.get("processInstanceId");
    }

    public BpmsTaskVO getByProcessInstanceId(String authKey, String processInstanceId) {
        String serviceURL = this.bpmsService + "/openapi/taskService/getTasksByProcessInstanceId.json";
        Request.Builder builder = new Request.Builder();
        builder.url(serviceURL);
        FormBody formBody = new FormBody.Builder()
                .add("processInstanceId", processInstanceId)
                .add("authKey", authKey)
                .add("pageIndex", "1")
                .add("pageSize", "15")
                .build();
        builder.post(formBody);
        Map<String, Object> contentMap = doExecute(builder, serviceURL);
        List<Map<String, Object>> entities = (List<Map<String, Object>>) contentMap.get("entities");

        if (CollectionUtils.isEmpty(entities)) {
            return null;
        }
        for (Map<String, Object> entity : entities) {
            BpmsTaskVO bpmsTaskVO = BpmsTaskVO.fromJsonMap(entity);
            if ("Agree".equals(bpmsTaskVO.getOutResult()) || "Disagree".equals(bpmsTaskVO.getOutResult())) {
                return bpmsTaskVO;
            }
        }
        return BpmsTaskVO.fromJsonMap(entities.get(0));
    }

    private Map<String, Object> doExecute(Request.Builder builder, String url) {
        HttpResponse httpResponse = httpClient.doExecute(builder.build());
        Map<String, Object> map = JsonUtils.from(httpResponse.getBody(), new TypeReference<>() {
        });
        log.debug("bpms doExecute response:{}", JsonUtils.toString(map));
        boolean success = (Boolean) map.get("success");
        if (!success) {
            throw new AmapException(AmapExceptionCode.COMMON_HTTP_ERROR,
                    url + ":BPMS接口调用失败:" + JsonUtils.toString(httpResponse.getBody()));
        }
        return (Map<String, Object>) map.get("content");
    }
}


